import random
import logging
import re
import hashlib
import hmac
import base64
from urllib.parse import quote
from django.contrib.auth import get_user_model
from django.http import JsonResponse, HttpResponseRedirect
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework_simplejwt.tokens import RefreshToken
from utils.rl_sms import send_verification_code, verify_code
from utils.JWTTool import JwtUtils
from utils.sns import DingTalkSNSClient
from utils.baidu_ocr import BaiduOcrClient
from utils.qiniu_storage import QiniuStorage
from utils.slider_verify import SliderVerify
from .serializers import UserSerializer
from django.core.cache import cache
from utils.baidu_living import verify_liveness_face
import uuid
import json
import logging
from django.utils import timezone
from django.http import HttpResponse
from decimal import Decimal, InvalidOperation
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from utils.wechat_native_pay import WeChatNativePayClient
from .models import Order

logger = logging.getLogger(__name__)

User = get_user_model()

# 微信支付可用性开关（避免 NameError）
WECHAT_PAY_AVAILABLE = getattr(settings, 'WECHAT_PAY_AVAILABLE', True)
# 1. 发送验证码视图
class SendCodeView(APIView):
    # 不需要JWT认证
    authentication_classes = []
    # 不需要权限认证，允许任何人访问
    permission_classes = []

    def post(self, request):
        from django.core.cache import cache
        
        # 从请求数据中获取手机号和验证令牌
        phone = request.data.get("phone")
        verify_token = request.data.get("verify_token")
        
        # 验证手机号格式
        if not phone or not re.match(r'^1[3-9]\d{9}$', phone):
            return Response(
                {"msg": "手机号格式错误"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # 如果提供了verify_token，验证令牌是否有效
        if verify_token:
            token_key = f"slider_token_{verify_token}"
            if not cache.get(token_key):
                return Response(
                    {"msg": "滑动验证已过期，请重新验证"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            # 验证通过后删除令牌（一次性使用）
            cache.delete(token_key)

        # 调用工具函数发送验证码
        code = send_verification_code(phone)
        # 返回成功响应，开发环境下返回验证码
        response_data = {"msg": "验证码已发送"}
        # 开发环境下返回验证码
        if settings.DEBUG:
            response_data["code"] = code
        return Response(response_data)


# 2. 手机号+验证码登录视图
class PhoneLoginView(APIView):
    # 不需要JWT认证
    authentication_classes = []
    # 不需要权限认证，允许任何人访问
    permission_classes = []

    def post(self, request):
        # 从请求数据中获取手机号、验证码和用户角色
        phone = request.data.get("phone")
        code = request.data.get("code")
        user_type = request.data.get("user_type", "jobseeker")  # 默认为求职者

        # 验证手机号格式
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return Response(
                {"msg": "手机号格式错误"},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 检查验证码是否存在
        if not code:
            return Response(
                {"msg": "验证码不能为空"},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 验证验证码是否正确且未过期
        if not verify_code(phone, code):
            return Response(
                {"msg": "验证码错误或已过期"},
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            # 尝试从数据库中获取用户
            user = User.objects.get(phone=phone)
            # 如果用户已存在，更新用户角色
            if user_type in ['jobseeker', 'recruiter']:
                user.user_type = user_type
                user.save()
        except User.DoesNotExist:
            # 如果用户不存在，则创建新用户
            user = User.objects.create_user(
                username=f'user_{phone}',  # 生成默认用户名
                phone=phone,  # 设置手机号
                user_type=user_type,  # 设置用户角色
                password=f'default_pwd_{random.randint(1000, 9999)}'
            )

        # 为用户生成JWT token
        refresh = RefreshToken.for_user(user)
        token = str(refresh.access_token)

        # 返回token信息和用户数据
        return Response({
            'token': token,  # 访问token
            'refresh': str(refresh),  # 刷新token
            'user': UserSerializer(user).data  # 用户信息
        })


@method_decorator(csrf_exempt, name='dispatch')
class SliderInitView(APIView):
    """初始化滑动验证：生成验证ID和缺口参数"""
    permission_classes = []  # 允许匿名访问
    authentication_classes = []  # 关闭默认JWT认证，避免未登录状态返回401

    def get(self, request):
        try:
            verify_data = SliderVerify.generate_verify()
            return Response({
                "success": True,
                "data": verify_data
            })
        except Exception as e:
            logger.error(f"滑动验证初始化失败：{str(e)}")
            return Response(
                {"success": False, "error": "生成验证信息失败"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


@method_decorator(csrf_exempt, name='dispatch')
class SliderCheckView(APIView):
    """校验滑动轨迹，返回验证令牌"""
    permission_classes = []  # 允许匿名访问
    authentication_classes = []  # 关闭默认JWT认证

    def post(self, request):
        # 记录收到的滑动验证请求数据，用于调试和监控
        data = request.data
        logger.info("收到滑动验证请求，数据: %s", data)

        # 必传参数校验：确保所有必需的参数都已提供
        required = ['verify_id', 'slider_left', 'track',
                    'start_time', 'end_time']
        # 检查是否有缺失的参数
        missing_params = [k for k in required if k not in data]
        if missing_params:
            # 记录警告日志并返回错误响应
            logger.warning("参数不完整，缺少: %s", missing_params)
            error_msg = f"参数不完整，缺少: {', '.join(missing_params)}"
            return Response(
                {"success": False, "error": error_msg},
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            # 参数类型转换和验证：将输入参数转换为正确的数据类型
            verify_id = str(data['verify_id'])
            try:
                # 将滑块位置和时间戳转换为整数
                slider_left = int(float(data['slider_left']))
                start_time = int(float(data['start_time']))
                end_time = int(float(data['end_time']))
            except (ValueError, TypeError) as e:
                # 如果转换失败，记录错误并返回400错误
                logger.error("参数类型转换失败: %s", str(e))
                return Response(
                    {"success": False, "error": "参数格式错误，请重新验证"},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证轨迹数据格式：确保轨迹数据是列表类型且不为空
            track_data = data['track']
            if not isinstance(track_data, list):
                # 如果轨迹数据不是列表类型，记录错误并返回400错误
                logger.error("轨迹数据格式错误，期望列表，实际: %s",
                           type(track_data))
                return Response(
                    {"success": False, "error": "轨迹数据格式错误"},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 检查轨迹数据是否为空
            if len(track_data) == 0:
                logger.warning("轨迹数据为空")
                return Response(
                    {"success": False, "error": "轨迹数据为空"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            # 调用工具类校验滑动轨迹
            # is_valid: 验证结果布尔值
            # result: 验证成功时为令牌，失败时为错误信息
            is_valid, result = SliderVerify.check_track(
                verify_id=verify_id,
                user_left=slider_left,
                track_data=track_data,
                start_time=start_time,
                end_time=end_time
            )
            
            # 根据验证结果返回相应响应
            if is_valid:
                # 验证成功，记录日志并返回包含验证令牌的响应
                logger.info("滑动验证成功，verify_id: %s", verify_id)
                return Response({
                    "success": True,
                    "verify_token": result  # 验证通过，返回令牌
                })
            else:
                # 验证失败，记录警告日志并返回错误信息
                logger.warning("滑动验证失败，verify_id: %s, 原因: %s",
                             verify_id, result)
                return Response({
                    "success": False,
                    "error": result
                }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            # 捕获并记录未预期的异常，返回500服务器错误
            logger.error("滑动轨迹校验异常：%s", str(e), exc_info=True)
            error_msg = f"验证处理失败: {str(e)}"
            return Response(
                {"success": False, "error": error_msg},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

# 生成钉钉登录链接
def dingtalk_login(request):
    """
    生成钉钉扫码登录的授权链接
    """
    # 钉钉授权URL参数
    redirect_uri = getattr(settings, 'DINGTALK_REDIRECT_URI', '')
    app_key = getattr(settings, 'DINGTALK_APP_KEY', '')

    if not redirect_uri or not app_key:
        return JsonResponse({"code": 500, "message": "钉钉配置缺失", "data": None})

    params = {
        "appid": app_key,
        "response_type": "code",
        "scope": "snsapi_login",  # 登录授权
        "state": "dingtalk_login",  # 用于防CSRF
        "redirect_uri": quote(redirect_uri)  # 回调URL需编码
    }
    # 构造授权URL
    auth_url = f"https://oapi.dingtalk.com/connect/qrconnect?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
    return JsonResponse({"code": 200, "message": "获取授权链接成功", "data": {"auth_url": auth_url}})


# 钉钉回调处理
# 签名验证函数
def verify_signature(signature, timestamp, nonce, state):
    params = [settings.DINGTALK_APP_SECRET, timestamp, nonce, state]
    params.sort()
    sign_str = "".join(params).encode("utf-8")
    hmac_code = hmac.new(settings.DINGTALK_APP_SECRET.encode("utf-8"), sign_str, digestmod=hashlib.sha256).digest()
    computed_signature = base64.b64encode(hmac_code).decode("utf-8")
    return computed_signature.lower() == signature.lower()


# dingtalk_callback 函数中不要导入 User
def dingtalk_callback(request):
    code = request.GET.get("code")
    state = request.GET.get("state", "")

    if not code:
        return JsonResponse({"error": "缺少code参数"}, status=400)

    try:
        sns_client = DingTalkSNSClient()
        user_info = sns_client.get_user_info_by_code(code)

        unionid = user_info.get("unionid")
        if not unionid:
            raise Exception("钉钉未返回unionid，无法关联用户")

        User = get_user_model()  # 在函数内动态获取用户模型
        user, created = User.objects.get_or_create(
            username=unionid,
            defaults={"is_active": True}
        )
        token = JwtUtils.getToken(str(user.id))

        return HttpResponseRedirect(f"http://localhost:5173/hrview?token={token}")

    except Exception as e:
        return JsonResponse({"error": f"登录处理失败: {str(e)}"}, status=500)

# 活体检测初始化接口
@method_decorator(csrf_exempt, name='dispatch')
class LivingInitView(APIView):
    """
    活体检测初始化视图类
    
    用于生成活体检测所需的验证ID和操作指引
    """
    # 不需要认证和权限检查
    authentication_classes = []
    permission_classes = []

    def get(self, request):
        """
        处理GET请求，初始化活体检测
        
        Returns:
            Response: 包含验证ID和操作指引的响应
        """
        try:
            # 生成16位随机字符串作为验证ID
            verify_id = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=16))
            # 将验证ID存储到缓存中，设置5分钟超时时间
            cache.set(f"living_verify_{verify_id}", True, timeout=300)
            # 定义活体检测操作指引
            instructions = [
                "请将脸对准框内",
                "眨眨眼或张张嘴"
            ]
            # 返回成功响应，包含验证ID和操作指引
            return Response({
                "success": True,
                "data": {"verify_id": verify_id, "instructions": instructions}
            })
        except Exception as e:
            # 记录错误日志
            logger.error("活体初始化失败: %s", str(e))
            # 返回失败响应
            return Response({"success": False, "error": "初始化失败"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


@method_decorator(csrf_exempt, name='dispatch')
class LivingCheckView(APIView):
    """
    活体检测校验视图类
    
    接收客户端上传的人脸图像进行活体检测，并在通过后签发一次性令牌
    """
    # 不需要认证和权限检查
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        """
        处理POST请求，执行活体检测校验
        
        Args:
            request: HTTP请求对象，应包含verify_id和face_image参数
            
        Returns:
            Response: 校验结果响应，成功时返回一次性令牌
        """
        # 获取请求数据
        data = request.data or {}
        verify_id = data.get('verify_id')
        face_image = data.get('face_image')  # base64格式图像数据（不含前缀）

        # 参数完整性校验
        if not verify_id or not face_image:
            return Response({"success": False, "error": "参数不完整"}, status=status.HTTP_400_BAD_REQUEST)

        # 验证会话是否有效
        if not cache.get(f"living_verify_{verify_id}"):
            return Response({"success": False, "error": "会话已过期，请重新初始化"}, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 基础图像质量校验 - 检查base64字符串长度
            if len(face_image) < 1000:
                return Response(
                    {"success": False, "error": "图像质量过低，请重新拍摄"},
                    status=status.HTTP_400_BAD_REQUEST,
                )
            
            # 校验base64编码有效性
            try:
                base64.b64decode(face_image, validate=True)
            except Exception:
                return Response(
                    {"success": False, "error": "图像编码无效"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # 调用百度AI接口进行活体检测
            ok, msg, score = verify_liveness_face(face_image)
            if not ok:
                return Response(
                    {"success": False, "error": msg, "score": score},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # 活体检测通过，生成一次性令牌
            token_src = f"{verify_id}:{random.random()}"
            living_token = hashlib.md5(token_src.encode()).hexdigest()
            # 存储令牌到缓存，设置5分钟超时
            cache.set(f"living_token_{living_token}", True, timeout=300)
            # 删除已使用的验证ID
            cache.delete(f"living_verify_{verify_id}")
            # 返回成功响应，包含令牌和检测得分
            return Response({"success": True, "living_token": living_token, "score": score})
        except Exception as e:
            # 记录错误日志
            logger.error("活体校验失败: %s", str(e))
            # 返回失败响应
            return Response({"success": False, "error": "活体检测失败，请重试"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@method_decorator(csrf_exempt, name='dispatch')
class IdCardOcrView(APIView):  # 身份证OCR识别接口
    """
    身份证OCR识别视图类
    用于处理用户上传的身份证正反面照片，通过百度OCR服务识别身份证信息
    """
    permission_classes = []  # 暂时移除认证要求，便于测试

    def post(self, request):
        """
        处理POST请求，执行身份证OCR识别
        """
        try:
            # 调试信息
            print("=" * 80)
            print("📥 OCR 请求调试信息：")
            print(f"  request.FILES: {request.FILES}")
            print(f"  request.POST: {request.POST}")
            print(f"  request.content_type: {request.content_type}")
            print("=" * 80)

            # 获取前端上传的照片
            front_image = request.FILES.get('front_image')  # 身份证正面照片
            back_image = request.FILES.get('back_image')  # 身份证背面照片

            print(f"  front_image: {front_image}")
            print(f"  back_image: {back_image}")

            # 验证是否上传了正反面照片
            if not front_image or not back_image:
                error_msg = "请上传身份证正反面照片"
                if not front_image:
                    error_msg += "（缺少正面照片）"
                if not back_image:
                    error_msg += "（缺少背面照片）"
                return Response({
                    "success": False,
                    "error": error_msg
                }, status=400)

            # 初始化OCR客户端
            ocr_client = BaiduOcrClient()

            # 识别正面
            print("🔍 开始识别正面...")
            front_result = ocr_client.recognize_id_card(front_image.read(), side="front")
            print(f"  正面识别结果: {front_result}")
            if not front_result["success"]:
                print(f"❌ 正面识别失败: {front_result.get('error')}")
                return Response(front_result, status=400)

            # 识别背面（有效期等）
            print("🔍 开始识别背面...")
            back_result = ocr_client.recognize_id_card(back_image.read(), side="back")
            print(f"  背面识别结果: {back_result}")
            if not back_result["success"]:
                print(f"❌ 背面识别失败: {back_result.get('error')}")
                return Response(back_result, status=400)

            # 整合结果并返回
            return Response({
                "success": True,
                "data": {
                    "front": front_result["data"],  # 正面识别数据
                    "back": back_result["data"]  # 背面识别数据
                }
            })
        except Exception as e:
            import traceback
            error_detail = traceback.format_exc()
            print("=" * 80)
            print("❌ OCR 错误详情：")
            print(error_detail)
            print("=" * 80)
            return Response({"success": False, "error": f"OCR 识别失败：{str(e)}"}, status=500)


@method_decorator(csrf_exempt, name='dispatch')
class IdCardVerificationSubmitView(APIView):  # 提交实名认证信息接口
    """
    实名认证信息提交视图类
    用于处理用户提交的实名认证信息，并更新用户状态
    """
    permission_classes = []  # 暂时移除认证要求，便于测试

    def post(self, request):
        """
        处理POST请求，保存用户实名认证信息
        """
        try:
            # 获取前端提交的身份证信息
            data = request.data

            # 检查用户是否登录
            if not request.user.is_authenticated:
                print("⚠️ 用户未登录，跳过数据库保存")
                return Response({
                    "success": True,
                    "message": "实名认证信息已验证（测试模式）"
                })

            # 获取当前登录用户
            user = request.user

            # 保存身份证信息到用户模型
            if hasattr(user, 'real_name'):
                user.real_name = data.get('name', '')  # 保存真实姓名
            if hasattr(user, 'id_card_number'):
                user.id_card_number = data.get('id_number', '')  # 保存身份证号

            # 标记为已实名认证
            if hasattr(user, 'is_realname_authenticated'):
                user.is_realname_authenticated = True  # 设置实名认证状态为已认证

            user.save()  # 保存用户信息

            print(f"✅ 用户 {user.id} 实名认证成功")
            print(f"   姓名: {data.get('name')}")
            print(f"   身份证号: {data.get('id_number')}")

            return Response({
                "success": True,
                "message": "实名认证提交成功"
            })

        except Exception as e:
            import traceback
            print("❌ 提交实名认证失败:")
            print(traceback.format_exc())
            return Response({
                "success": False,
                "error": f"提交失败：{str(e)}"
            }, status=500)


@method_decorator(csrf_exempt, name='dispatch')
class IdCardUploadView(APIView):  # 身份证照片上传接口（七牛云存储）
    """
    身份证照片上传视图类
    用于将用户身份证正反面照片上传到七牛云存储服务
    """
    permission_classes = []  # 暂时移除认证要求，便于测试

    def post(self, request):
        """
        处理POST请求，上传身份证照片到七牛云
        """
        # 获取上传的文件和参数
        front_file = request.FILES.get('front_image')  # 身份证正面照片文件
        back_file = request.FILES.get('back_image')  # 身份证背面照片文件

        # 验证是否上传了正反面照片
        if not front_file or not back_file:
            return Response({"error": "请上传身份证正反面照片"}, status=400)

        # 初始化七牛云存储工具
        qiniu_storage = QiniuStorage()

        try:
            # 如果用户已登录，使用用户ID；否则使用默认值
            user_id = request.user.id if request.user.is_authenticated else 0

            # 上传正面照片
            front_url, front_key = qiniu_storage.upload_file(
                file_data=front_file.read(),  # 读取文件数据
                file_name=front_file.name,  # 文件名
                user_id=user_id,  # 用户ID，用于生成存储路径
                side="front"  # 照片类型：正面
            )

            # 上传背面照片
            back_url, back_key = qiniu_storage.upload_file(
                file_data=back_file.read(),  # 读取文件数据
                file_name=back_file.name,  # 文件名
                user_id=user_id,  # 用户ID，用于生成存储路径
                side="back"  # 照片类型：背面
            )

            # 将文件key存入用户表或实名认证表，便于后续管理
            # 如果User模型有这些字段且用户已登录，则保存
            if request.user.is_authenticated and hasattr(request.user, 'id_card_front_key'):
                request.user.id_card_front_key = front_key  # 保存正面照片key
                request.user.id_card_back_key = back_key  # 保存背面照片key
                request.user.save()

            return Response({
                "success": True,
                "front_url": front_url,  # 带签名的临时访问URL（正面）
                "back_url": back_url  # 带签名的临时访问URL（背面）
            })
        except Exception as e:
            import traceback
            error_detail = traceback.format_exc()
            print("=" * 80)
            print("❌ 上传错误详情：")
            print(error_detail)
            print("=" * 80)
            return Response({"error": f"上传失败：{str(e)}"}, status=500)

class WeChatNativePayCreateView(APIView):
    """创建微信扫码支付订单 生成二维码链接"""
    # 临时允许匿名访问用于测试，生产环境应改为 [IsAuthenticated]
    permission_classes = []  # 测试环境允许匿名访问

    def post(self, request):
        try:
            if not WECHAT_PAY_AVAILABLE:
                return Response({
                    "error": "微信支付功能不可用"
                }, status=503)
            
            # 获取前端参数：优先使用现有订单，其次在已登录+提供金额时临时创建订单
            data = request.data or {}
            order_id = data.get("order_id")
            inline_amount = data.get("amount")  # 允许在缺少 order_id 时传金额（元）

            order = None
            if order_id:
                try:
                    # 如果带了登录态，则校验归属；匿名则仅按ID查
                    if request.user.is_authenticated:
                        order = Order.objects.get(id=order_id, user=request.user)
                    else:
                        order = Order.objects.get(id=order_id)
                    if order.paid:
                        return Response({"error": "订单已支付"}, status=400)
                except Order.DoesNotExist:
                    return Response({"error": f"订单不存在: {order_id}"}, status=400)
                except Exception as e:
                    logger.error(f"查询订单失败: {str(e)}")
                    return Response({"error": f"查询订单失败: {str(e)}"}, status=500)
            else:
                # 无 order_id：如果已登录且提供了 amount，则为当前用户创建临时订单（便于联调）
                if request.user.is_authenticated and inline_amount is not None:
                    try:
                        # 金额元 -> Decimal 校验
                        amount_dec = Decimal(str(inline_amount))
                        if amount_dec <= Decimal("0"):
                            return Response({"error": "金额必须大于0"}, status=400)
                    except (InvalidOperation, TypeError, ValueError):
                        return Response({"error": f"金额格式错误: {inline_amount}"}, status=400)
                    try:
                        order = Order.objects.create(
                            user=request.user,
                            amount=amount_dec,
                            description=data.get("description") or "临时订单"
                        )
                        order_id = str(order.id)
                    except Exception as e:
                        logger.error(f"创建临时订单失败: {str(e)}")
                        return Response({"error": f"创建临时订单失败: {str(e)}"}, status=500)
                else:
                    # 无 order_id 且无法创建订单的情况
                    if not request.user.is_authenticated:
                        return Response(
                            {"error": "请先登录后再进行支付；或提供有效的订单ID"},
                            status=401
                        )
                    elif inline_amount is None:
                        return Response(
                            {"error": "请提供订单ID或支付金额（amount）"},
                            status=400
                        )
                    else:
                        # 这种情况理论上不会到达，但为了安全还是保留
                        return Response(
                            {"error": "无法创建订单，请稍后重试"},
                            status=400
                        )

            # 生成唯一商户订单号（避免重复）
            out_trade_no = f"wx_native_{uuid.uuid4().hex[:16]}"
            # 订单金额（单位：分，需转换）
            try:
                # 使用 Decimal 避免浮点误差
                total_amount = int((Decimal(str(order.amount)) * Decimal("100")).to_integral_value())
                if total_amount <= 0:
                    return Response({"error": f"订单金额必须大于0: {order.amount}"}, status=400)
            except (InvalidOperation, ValueError, TypeError) as e:
                logger.error(f"订单金额转换失败: {order.amount}, 错误: {str(e)}")
                return Response({"error": f"订单金额格式错误: {order.amount}"}, status=400)

            # 调用工具类创建扫码支付订单
            try:
                pay_client = WeChatNativePayClient()
            except Exception as e:
                logger.exception(f"初始化微信支付客户端失败: {str(e)}")
                return Response({
                    "error": f"微信支付配置错误: {str(e)}。请检查 settings.py 中的 WECHAT_PAY 配置"
                }, status=500)
            
            result = pay_client.create_native_order(
                out_trade_no=out_trade_no,
                total_amount=total_amount,
                description=f"订单-{order.id}"  # 订单描述
            )

            if result["success"]:
                # 保存商户订单号到数据库
                order.out_trade_no = out_trade_no
                order.save()
                return Response({
                    "success": True,
                    "code_url": result["code_url"],  # 二维码链接（前端用于生成二维码）
                    "out_trade_no": out_trade_no,  # 用于后续查询支付状态
                    "order_id": str(order.id)  # 返回订单ID（便于前端使用）
                })
            # 透出更明确的错误
            return Response({
                "error": result.get("error", "创建支付订单失败"),
                "order_id": order_id
            }, status=400)
            
        except Exception as e:
            logger.exception(f"创建支付订单异常: {str(e)}")
            return Response({
                "error": f"服务器内部错误: {str(e)}"
            }, status=500)


@method_decorator(csrf_exempt, name='dispatch')
class WeChatPayNotifyView(APIView):
    """微信支付结果回调通知接口（微信服务器主动调用）"""
    permission_classes = []  # 允许匿名访问（微信服务器无认证）
    def post(self, request):
        if not WECHAT_PAY_AVAILABLE:
            logger.error("微信支付功能不可用，无法处理回调")
            return HttpResponse("FAIL")
        
        pay_client = WeChatNativePayClient()
        # 验证回调签名并解析数据
        verify_result = pay_client.verify_pay_notify(request)
        if not verify_result["success"]:
            logger.error(f"支付回调验证失败: {verify_result['error']}")
            return HttpResponse("FAIL")  # 微信要求失败返回"FAIL"

        # 处理支付成功逻辑
        if verify_result["trade_state"] == "SUCCESS":
            try:
                # 更新订单状态为已支付
                order = Order.objects.get(out_trade_no=verify_result["out_trade_no"])
                order.paid = True
                order.status = 'paid'
                order.paid_time = timezone.now()
                order.transaction_id = verify_result["data"]  # 微信支付订单号
                order.save()
                logger.info(f"订单{verify_result['out_trade_no']}支付成功")
            except Exception as e:
                logger.error(f"更新订单状态失败: {str(e)}")

        # 必须返回"SUCCESS"给微信，否则会重复发送通知
        return HttpResponse(json.dumps({"code": "SUCCESS", "message": "成功"}))


class WeChatPayQueryView(APIView):
    """查询微信支付订单状态（前端轮询用）"""
    # 允许匿名访问，与创建支付接口保持一致
    permission_classes = []

    def get(self, request):
        if not WECHAT_PAY_AVAILABLE:
            return Response({
                "error": "微信支付功能不可用"
            }, status=503)
        
        out_trade_no = request.query_params.get("out_trade_no")
        if not out_trade_no:
            return Response({"error": "缺少商户订单号"}, status=400)

        # 先尝试从数据库查询订单状态（如果已更新）
        try:
            order = Order.objects.get(out_trade_no=out_trade_no)
            # 如果订单已标记为已支付，直接返回
            if order.paid:
                return Response({
                    "success": True,
                    "is_paid":   True,
                    "trade_state": "SUCCESS",
                    "message": "支付成功"
                })
        except Order.DoesNotExist:
            # 订单不存在，继续查询微信支付
            pass
        except Exception as e:
            logger.warning(f"查询订单状态失败: {str(e)}")

        # 查询微信支付订单状态
        try:
            pay_client = WeChatNativePayClient()
            result = pay_client.query_order(out_trade_no=out_trade_no)
            if result["success"]:
                # 判断是否支付成功（SUCCESS表示成功）
                is_paid = result["trade_state"] == "SUCCESS"
                # 如果支付成功，更新数据库订单状态
                if is_paid:
                    try:
                        order = Order.objects.get(out_trade_no=out_trade_no)
                        if not order.paid:
                            order.paid = True
                            order.status = 'paid'
                            order.save()
                            logger.info(f"订单 {out_trade_no} 支付状态已更新")
                    except Order.DoesNotExist:
                        logger.warning(f"订单 {out_trade_no} 不存在于数据库")
                    except Exception as e:
                        logger.error(f"更新订单状态失败: {str(e)}")
                
                return Response({
                    "success": True,
                    "is_paid": is_paid,
                    "trade_state": result["trade_state"],
                    "message": result.get("trade_state_desc", "")
                })
            return Response({"error": result.get("error", "查询失败")}, status=400)
        except Exception as e:
            logger.error(f"查询微信支付订单状态异常: {str(e)}", exc_info=True)
            return Response({"error": f"查询失败: {str(e)}"}, status=500)